//
// Created by 陈奕锟 on 2022/11/20.
//

#ifndef AUTOMATICTELLER_TEMPLATEDISPATCHER_HPP
#define AUTOMATICTELLER_TEMPLATEDISPATCHER_HPP

#endif //AUTOMATICTELLER_TEMPLATEDISPATCHER_HPP
#pragma once

#include "message.hpp"
#include "dispatcher.hpp"

namespace messaging
{
    template<typename PreviousDispatcher, typename Msg, typename Func>
    class TemplateDispatcher
    {
    private:
        queue* q;
        PreviousDispatcher* prev;
        Func f;
        bool chained;

        TemplateDispatcher(TemplateDispatcher const&) = delete;
        TemplateDispatcher& operator= (TemplateDispatcher const&) = delete;

        template<typename Dispatcher, typename OtherMsg, typename OtherFunc>
        friend class TemplateDispatcher;    // * 根据模版类TemplateDispatcher具体实现化的各种类型互为友类

        void wait_and_dispatch()
        {
            for (;;)
            {
                auto msg = q -> wait_and_pop();

                if ( dispatch(msg) )
                    break;
                // * 如果消息已经处理，则跳出无限循环
            }
        }

        bool dispatch(std::shared_ptr<message_base> const& msg)
        {
            if (
                    wrapped_message<Msg>* wrapper =
                            dynamic_cast< wrapped_message<Msg>* >( msg.get() )
                            )
            // * 检查消息类型并调用相应的处理函数
            {
                f(wrapper -> contents);

                return true;
            }
            else
            {
                return prev -> dispatch(msg);
                // * 链接前一个dispatcher对象，形成连锁调用
            }
        }

    public:
        TemplateDispatcher(TemplateDispatcher&& other) noexcept
            : q(other.q), prev(other.prev), f( std::move(other.f) ), chained(other.chained)
        {
            other.chained = true;
        }

        TemplateDispatcher(queue* i_q, PreviousDispatcher* i_prev, Func&& i_f)
            : q(i_q), prev(i_prev), f( std::forward<Func>(i_f) ), chained(false)
        {
            i_prev -> chained = true;
        }

        template<typename OtherMsg, typename OtherFunc>
        TemplateDispatcher<TemplateDispatcher, OtherMsg, OtherFunc>
        handle(OtherFunc&& otherFunc)   // * 形成链接链， 引入更多处理函数
        {
            return
                TemplateDispatcher<TemplateDispatcher, OtherMsg, OtherFunc>(
                    q, this, std::forward<OtherFunc>(otherFunc)
                    );
        }

        ~TemplateDispatcher() noexcept(false)
        {
            if (!chained)
            {
                wait_and_dispatch();
            }
        }
    };
}